<?php
abstract class Mozg_Controller_Instance extends Mozg_Env_Base
{
    protected $_ctrlName = '';
    protected $_moduleName = '';

    protected $_detector;

    public function __construct($protName, $envName)
    {
    	parent::__construct($protName, $envName);
    	
        $this->_detector = new Mozg_Detector($this);
		list($this->_moduleName, $this->_ctrlName) = $this->_detector->last();

        $this->RequireLang();
        
        $this->ControllerInit();
    }

    protected function RequireLang()
    {
    	foreach ($this->_detector as $component)
    	{
    		if (strlen($component[0]) && strlen($component[1]))
    		{
    			Mozg_Lang::Required('module_' .strtolower($component[0]). '_ctrl_' .strtolower($component[1]));
    		}
    	}
    }

    protected function GetTpl($name = '')
    {
    	foreach ($this->_detector as $component)
    	{
    		try
    		{
    			return Mozg::Tpl($name, $component[0], $component[1], $this->_detector);
    		}
    		catch (Exception $e)
    		{
    			
    		}
    	}

    	throw new Mozg_Exception_NotFound(Mozg_Lang::_('Template ' .$name. ' not found in %s', get_class($this)));
    }
	
    /**
		Инициализация контроллера
     */
    protected function ControllerInit(){}
    
    /**
		Инициализация Pr экшена
     */
    protected function PrimaryActionInit ($basicActionName){}
    
    /**
		возвращает имя контроллера
     */
    final public function GetName()
    {
        return $this->_ctrlName;
    }
    
    final public function GetModuleName()
    {
        return $this->_moduleName;
    }

    /**
		возвращает тип экшена по его имени.
		return
		1 - PrAction
		2 - ScAction
		0 - экшен не найден или неправильный
     */
    public function GetActionType ($actionName)
    {
        if (method_exists($this, $actionName)) return 0;
        elseif (method_exists($this, $actionName . 'Action'))
        {
	        switch (substr($actionName, -2))
	        {
	            case 'Pr':
	                return 1;
	            case 'Sc':
	                return 2;
	        }
        }
        return 0;
    }
    
    /**
		сюда можно впихнуть дополнительную проверку,
		после того как юзер прошёл основную проверку
	*/
    public function CheckAccessWithUserGranted()
    {
		return true;
    }
    
    public function CheckAccess($basicActionName)
    {
        if (Mozg::User()->CheckAccess($this->GetModuleName(), $this->GetName(), $basicActionName))
        {
        	return $this->GetModule($this->GetModuleName())->CheckAccessWithUserGranted($this, $basicActionName);
        }
        	
        return false;
    }
    /**
     	Пример:
		$actionName = 'methodPr'
		или
		$actionName = 'methodSc'
	*/
    public function __call ($actionName, $args)
    {
        $actionType = $this->GetActionType($actionName);
        if (!$actionType)
        {
            throw new Mozg_Exception_NotFound(Mozg_Lang::_('METHOD_%_OF_CONTROLLER_%_NOT_DEFINED', $actionName, $this->GetName()));
        }
            
        $basicActionName = substr($actionName, 0, -2);
            
            // проверяем доступ
        if (!$this->CheckAccess($basicActionName))
        {
            $postFix = 1 == $actionType ? 'Pr' : 'Sc';
            
            /**
             * TODO: throw exceptions here instead of calling controllers
             */
            if (!Mozg::User()->GetId())
            {
            	throw new Mozg_Exception_NotAuthorized('Method is available for authorized users');
            }
            else
            {
            	throw new Mozg_Exception_NotAcceptable('Access denied');
            }
        }

        $prepareStatus = true;
        if (1 == $actionType) $prepareStatus = $this->PrimaryActionInit($basicActionName);
        
        if ($prepareStatus === false) return;
        
        return call_user_func_array(array($this, $actionName . 'Action'), $args);
    }
    
    public function ActionExists($actionName)
    {
    	return method_exists($this, $actionName. 'Action');
    }
    
    public function GetCtrl($ctrlName)
    {
    	foreach ($this->_detector as $component)
    	{
    		try
    		{
    			if ($component[0])
    			{
    				return Mozg::Ctrl($component[0], $ctrlName, $this->GetProt(), $this->GetEnv());
    			}
    		}
    		catch (Exception $e)
    		{
    			
    		}
    	}

    	throw new Mozg_Exception_NotFound(Mozg_Lang::_('Controller ' .$ctrlName. ' not found in %s', get_class($this)));
    }
    
    public function GetModule($moduleName)
    {
    	return Mozg::Module($moduleName, $this->GetProt(), $this->GetEnv());
    }
    
    public function PrAction()
    {
    	
    }
    
    public function defaultPrAction()
    {
    	return $this->Pr();
    }
}